/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package distFileSystem;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import database.SqlDatabase;
import java.sql.SQLException;
import java.util.List;

/**
 *
 * @author Du
 */
public class Master implements Runnable {

    /**
     * @param args the command line arguments
     */
    private ServerSocket mestre;
    private Socket conNo;
    private InputStream in;
    private OutputStream out;
    private int servPort;
    private SqlDatabase bd;

    public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
        Master mestre = new Master(Integer.parseInt(args[0]));

        while (true) {
            System.out.println("Servidor aguardando conexao...");
            ServerSocket me = mestre.getServSocket();
            Socket sock = me.accept();
            mestre.setconNo(sock);

            Thread t = new Thread(mestre);
            t.start();
        }

    }

    private Master(int servPort) throws IOException {
        this.servPort = servPort;
        mestre = new ServerSocket(servPort);
        this.bd = new SqlDatabase(Globals.DB_FILENAME, Globals.DB_LOGNAME);
    }

    public void setconNo(Socket sock) {
        conNo = sock;
    }

    public ServerSocket getServSocket() {
        return mestre;
    }

    @Override
    public void run() {
        try {
            in = conNo.getInputStream();     //recebe mensagem cliente
            out = conNo.getOutputStream();   //envia resposta para cliente

            String entrada = new String();             //string para receber o nome do arquivo
            int opcao = 1;
            Scanner scan = new Scanner(in);
            PrintStream envia = new PrintStream(out);
            //recebe a opção da operação a ser realizada
            if (scan.hasNext()) {
                opcao = Integer.parseInt(scan.nextLine());
            }

            //recebe o nome do arquivo
            if (scan.hasNext()) {
                entrada = scan.nextLine();
            }

            if (opcao == 1) { //opcao de copiar arquivo

                //procurar o arquivo no BD e recuperar o tamanho e o host do arquivo
                List list_hosts = null;
                if (bd.exists(entrada)) {
//                    envia.println("0");
                    list_hosts = bd.searchCopies(entrada);
                } else {
//                    envia.println("1");
                    System.out.println("Arquivo inexistente.");
                }

                // passa o nó de um cliente que tem o arquivo
                String end = (String) list_hosts.get(0);
                // passa o tamanho do arquivo
                int tamArq = bd.getSize(entrada);

                // envia as informações para o cliente
                envia.println(end);
                envia.println(String.valueOf(tamArq));

                bd.createCopy(entrada, end); // cria copia no bd

            } else if (opcao == 2) {  //opcao de excluir arquivos
                //Mestre deve verificar se o arquivo não existe, se sim retorna 0, 1 caso contrário
                if (!bd.exists(entrada)) {
                envia.println("0");
                } else {
                envia.println("1");
                }
                //SUBSTITUIR 'node3' pelo nome do nó que possui o arquivo (fazer com todos os nós que possuem cópia também)
                Socket clnt = new Socket("node3", servPort);
                OutputStream ops = clnt.getOutputStream();
                PrintStream ps = new PrintStream(ops);
                //envia código de mestre ao nó que possui o arquivo para deletá-lo
                ps.println("2");
                //envia o nome do arquivo a ser deletado
                ps.println(entrada);
                ps.flush();
                ps.close();

                envia.println("1");

                //exclui do BD
                //Exemplo de DELETE por nome do arquivo
                /*if (bd.getFlag("doc_duplicate.txt").equalsIgnoreCase("-")) {
                bd.delete("doc_duplicate.txt");
                } else if (bd.getFlag("doc_duplicate.txt").equalsIgnoreCase("r")) {
                while(bd.countCopiesBeingRead(entrada) > 0){
                continue;
                }
                //bd.delete("doc_duplicate.txt");
                } else {
                System.out.println("Impossivel deletar: arquivo 'doc_duplicate.txt' sendo escrito");
                }*/

            } else if (opcao == 3) {  //opcao de criar arquivos
                if (bd.exists(entrada)) {
                    envia.println("0");
                } else {
                    envia.println("1");
                }

                String nArq = entrada;
                int tamArq = 0;
                String nomeNo = null;
                //recebe o tamanho do arquivo
                if (scan.hasNext()) {
                    tamArq = Integer.parseInt(scan.nextLine());
                }
                //recebe o nome do nó que está criando o arquivo
                if (scan.hasNext()) {
                    nomeNo = scan.nextLine();
                }
                //cria a tupla no banco de dados
                bd.create(nArq, tamArq, nomeNo);

            } else { //caso nenhum seja escolhida
            }


            envia.flush();
            in.close();
            out.close();
            envia.close();
            conNo.close();
        } catch (IOException ex) {
            Logger.getLogger(Master.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
